#include "client.h"
#include <cstdlib>
#include <iostream>
#include <netdb.h>
#include <cstring>

using namespace std;

int main(void)
{
  client cl;
  cl.init();
  cl.communicate();
  cl.deinit();
  exit(0);	
}

void client::init()
{	
  initial_state = 0;
  adresse.sin_family = AF_INET;
  adresse.sin_port = htons(2233); // here specify the port number 
  inet_aton("127.0.0.1",&ip); // here specify the IP-adress of the server 
  server = gethostbyaddr((char*) &ip,sizeof(ip),AF_INET);
  if (server == 0) {
    cout << "client: wrong ip-adress of server" << endl;
    exit(1);
  }
  memcpy(&adresse.sin_addr,server->h_addr_list[0],sizeof(adresse.sin_addr));
  
  if ( (socket_id = socket(PF_INET, SOCK_STREAM,0)) < 0) {	 
    cout << "client: cannot create socket" << endl;
    exit(1);
  }
  
  // connecting to server
  if (connect(socket_id,(struct sockaddr *) &adresse, sizeof(adresse))) {
    cout << "client: cannot connect to server" << endl;
    exit(1);
  }
  
  // waiting for initial information from server  
  int j = 0;
  while(true) {
    read(socket_id,&information[j],1);
    if (information[j] == '\n') {
      information[j] = '\0';
      break;
    }
    j++;
  }	
  
  // parse string from server
  char* p = new char[255];         
  char* p_save = p;	
  strcpy(p,information);
  observation_dim = (int) atof(p);      
  p = strchr(p,' ');  
  p++; 
  action_dim = (int) atof(p);      
  p = strchr(p,' ');  
  p = p_save;
  delete[] p;
  
  observation = new double[observation_dim];
  cout << "client: initial information from server:" << endl;
  cout << "dimension of observation space: " << observation_dim << endl;
  cout << "dimension of action space:" << action_dim << endl << endl; 	
  
  // send acknowledgement to server 
  sprintf(information,"ack\n"); 
  cout << "client writes acknowledgement: " << information << endl;
  if (write(socket_id,information,strlen(information)) < 0) {
    cout << "client: communication with server failed"  << endl;
    exit(1);
  }
  
}

void client::communicate()
{ 	
  int j = 0;	
  char message[255];
  char* p = new char[255];
  char* p_save = p;
  for (int i = 0; i < 255;i++) {
    information[i] = '\0';
    message[i] = '\0';
    p[i] = '\0';
  }
  
  while (true) {			
    j = 0;
    while(true) {
      read(socket_id,&information[j],1);    
      if (information[j] == '\n') {				
	information[j+1] = '\0';
	break;			
      }
      j++;							
    }
    
    // parse message from server		
    p = p_save;  
    strcpy(p,information);
    
    j = 0;
    while (*p != ' ') {
      message[j] = *p;		
      p++;			
      j++;
    }
    p++;
    message[j] = '\0';
    
    cout << "client reads type of message: " << message << endl;    
    if (strcmp(message,"observation") == 0) {			 
      // observation information of plant					
      for (int i = 0; i < observation_dim;i++){      
	observation[i] = atof(p);         
	p = strchr(p,' ');  
	p++;
      }		 	       	
      
      cout << "client reads observation: ";
      for (int i = 0; i < observation_dim; i++)
	cout << observation[i] << " ";     
      cout << endl;
      
      // sending response to server (control signal)
      // insert here code for calculating the control signal
      double action = -10 + drand48()*20; // example action
      sprintf(information,"%f\n",action);
      cout << "client writes control signal: " << information;
      if (write(socket_id,information,strlen(information)) < 0) {
	cout << "communication with server failed" << endl;				
	exit(1);
      }
      continue;
    }

    if (strcmp(message,"reward") == 0) {
      // reward information of plant
      double reward = atof(p);     
      cout << "client reads reward signal: " << reward << endl << endl;
      continue;
    }
    
    if (strcmp(message,"initial") == 0) {    
      state_dim = (int) atof(p);      
      p = strchr(p,' ');  
      p++; 
      // server asks for checking the initial state of episode
      if (initial_state == 0)
	initial_state = new double[state_dim];
      for (int i = 0; i < state_dim;i++){      
	initial_state[i] = atof(p);         
	p = strchr(p,' ');  
	p++;
      }		 	
      for (int i = 0; i < observation_dim;i++){      
	observation[i] = atof(p);         
	p = strchr(p,' ');  
	p++;
      }	
          			 		
      cout << "client reads initial state: ";
      for (int i = 0; i < state_dim; i++)
	cout << initial_state[i] << " "; 
      cout << endl;
      cout << "client reads initial observation: ";
      for (int i = 0; i < observation_dim; i++)
	cout << observation[i] << " "; 
      cout << endl;
      
      // client (optionally) modifies initial state and sends it back to server		 
      *information = '\0';	 	
      for(int i = 0; i < state_dim;i++) {
	char state[255];
	sprintf(state,"%f ",initial_state[i]);  
	strcat(information,state);
      }
      strcat(information,"\n\0");  
      
      cout << "client writes initial state: " << information << endl;
      if (write(socket_id,information,strlen(information)) < 0) {
	cout << "communication with server failed" << endl;		
	exit(1);
      }
      continue;
    }	
    
    if (strcmp(message,"start") == 0) {      
      cout << "client reads: new episode started" << endl;
        // initial observation of episode
      for (int i = 0; i < observation_dim;i++){      
	observation[i] = atof(p);         
	p = strchr(p,' ');  
	p++;
      }		 	    
      
      cout << "client reads initial observation: ";
      for (int i = 0; i < observation_dim; i++)
	cout << observation[i] << " ";     
      cout << endl << endl;
      continue;
    }
    
    if (strcmp(message,"stop") == 0) {
      cout << "client reads: episode has stopped" << endl;
      // final observation of episode 
      for (int i = 0; i < observation_dim;i++){      
	observation[i] = atof(p);         
	p = strchr(p,' ');  
	p++;
      }	
      // final reward on episode
      double final_reward = atof(p);
      p = strchr(p,' ');
      p++;
      // is final state of episode a terminal state?
      int terminal = (int) atof(p);
      p = strchr(p,' ');
      p++;    
      cout << "client reads final observation: ";
      for (int i = 0; i < observation_dim; i++)
	cout << observation[i] << " ";     
      cout << endl;
      cout << "client reads final reward: " << final_reward << endl;
      cout << "clent reads terminal state: " << terminal << endl << endl;      
      continue;
    }
    
    if (strcmp(message,"exit") == 0) {
      cout << "client reads: server quits communication" << endl;
      return;
    }
  }							
}

void client::deinit()
{
  close(socket_id);
}


